package com.ruoyi.system.utils.file;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.net.URL;
import java.util.Date;
import java.util.UUID;

import com.aliyun.oss.OSS;
import com.aliyun.oss.model.ObjectMetadata;
import com.aliyun.oss.model.PutObjectRequest;
import com.ruoyi.common.utils.file.MimeTypeUtils;
import com.ruoyi.system.config.OssConfig;
import org.apache.commons.io.FilenameUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import com.ruoyi.common.exception.file.FileNameLengthLimitExceededException;
import com.ruoyi.common.exception.file.FileSizeLimitExceededException;
import com.ruoyi.common.exception.file.InvalidExtensionException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;

/**
 * 阿里云OSS文件上传工具类
 */
@Component
public class OssFileService {
    /**
     * 默认大小 50M
     */
    public static final long DEFAULT_MAX_SIZE = 50 * 1024 * 1024;

    /**
     * 默认的文件名最大长度 100
     */
    public static final int DEFAULT_FILE_NAME_LENGTH = 100;

    @Autowired
    private OSS ossClient;

    @Autowired
    private OssConfig ossConfig;

    /**
     * 上传文件
     *
     * @param file 文件
     * @param baseDir 相对路径
     * @return 返回上传成功的文件访问路径
     * @throws Exception
     */
    public String uploadFile(MultipartFile file, String baseDir) throws Exception {
        int fileNamelength = file.getOriginalFilename().length();
        if (fileNamelength > DEFAULT_FILE_NAME_LENGTH) {
            throw new FileNameLengthLimitExceededException(DEFAULT_FILE_NAME_LENGTH);
        }

        assertAllowed(file);

        String fileName = extractFilename(file, baseDir);

        try (InputStream inputStream = file.getInputStream()) {
            // 创建上传Object的Metadata
            ObjectMetadata metadata = new ObjectMetadata();
            metadata.setContentLength(inputStream.available());
            metadata.setCacheControl("no-cache");
            metadata.setHeader("Pragma", "no-cache");
            metadata.setContentType(getContentType(fileName));
            metadata.setContentDisposition("inline;filename=" + fileName);

            // 上传文件
            PutObjectRequest putObjectRequest = new PutObjectRequest(ossConfig.getBucketName(), fileName, inputStream, metadata);
            ossClient.putObject(putObjectRequest);

            // 返回文件访问路径
            return getFileUrl(fileName);
        } catch (Exception e) {
            throw new Exception(e.getMessage());
        }
    }

    /**
     * 上传字节数组
     *
     * @param content 字节数组
     * @param baseDir 相对路径
     * @param fileName 文件名
     * @return 返回上传成功的文件访问路径
     * @throws Exception
     */
    public String uploadByteArray(byte[] content, String baseDir, String fileName) throws Exception {
        String path = baseDir + "/" + DateUtils.datePath() + "/" + UUID.randomUUID().toString().replaceAll("-", "") + "." + FilenameUtils.getExtension(fileName);

        try (ByteArrayInputStream inputStream = new ByteArrayInputStream(content)) {
            // 创建上传Object的Metadata
            ObjectMetadata metadata = new ObjectMetadata();
            metadata.setContentLength(content.length);
            metadata.setCacheControl("no-cache");
            metadata.setHeader("Pragma", "no-cache");
            metadata.setContentType(getContentType(path));
            metadata.setContentDisposition("inline;filename=" + path);

            // 上传文件
            PutObjectRequest putObjectRequest = new PutObjectRequest(ossConfig.getBucketName(), path, inputStream, metadata);
            ossClient.putObject(putObjectRequest);

            // 返回文件访问路径
            return getFileUrl(path);
        } catch (Exception e) {
            throw new Exception(e.getMessage());
        }
    }

    /**
     * 删除文件
     *
     * @param fileName 文件名
     */
    public void deleteFile(String fileName) {
        if (StringUtils.isEmpty(fileName)) {
            return;
        }
        
        // 如果是完整URL，提取文件名
        if (fileName.startsWith(ossConfig.getDomain())) {
            fileName = fileName.substring(ossConfig.getDomain().length() + 1);
        }
        
        ossClient.deleteObject(ossConfig.getBucketName(), fileName);
    }

    /**
     * 获取文件访问URL
     *
     * @param fileName 文件名
     * @return 文件访问URL
     */
    public String getFileUrl(String fileName) {
        if (StringUtils.isEmpty(fileName)) {
            return "";
        }
        
        // 如果已经是完整URL，直接返回
        if (fileName.startsWith("http")) {
            return fileName;
        }
        
        // 返回文件访问路径
        return ossConfig.getDomain() + "/" + fileName;
    }

    /**
     * 获取带签名的临时访问URL
     *
     * @param fileName 文件名
     * @param expiration 过期时间（毫秒）
     * @return 临时访问URL
     */
    public String getSignedUrl(String fileName, long expiration) {
        if (StringUtils.isEmpty(fileName)) {
            return "";
        }
        
        // 如果是完整URL，提取文件名
        if (fileName.startsWith(ossConfig.getDomain())) {
            fileName = fileName.substring(ossConfig.getDomain().length() + 1);
        }
        
        // 设置URL过期时间
        Date expireDate = new Date(System.currentTimeMillis() + expiration);
        
        // 生成URL
        URL url = ossClient.generatePresignedUrl(ossConfig.getBucketName(), fileName, expireDate);
        
        return url.toString();
    }

    /**
     * 获取文件类型
     *
     * @param fileName 文件名
     * @return 文件类型
     */
    private String getContentType(String fileName) {
        String extension = FilenameUtils.getExtension(fileName);
        
        if ("jpg".equalsIgnoreCase(extension) || "jpeg".equalsIgnoreCase(extension)) {
            return "image/jpeg";
        } else if ("png".equalsIgnoreCase(extension)) {
            return "image/png";
        } else if ("gif".equalsIgnoreCase(extension)) {
            return "image/gif";
        } else if ("bmp".equalsIgnoreCase(extension)) {
            return "image/bmp";
        } else if ("webp".equalsIgnoreCase(extension)) {
            return "image/webp";
        } else if ("pdf".equalsIgnoreCase(extension)) {
            return "application/pdf";
        } else if ("doc".equalsIgnoreCase(extension)) {
            return "application/msword";
        } else if ("docx".equalsIgnoreCase(extension)) {
            return "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
        } else if ("xls".equalsIgnoreCase(extension)) {
            return "application/vnd.ms-excel";
        } else if ("xlsx".equalsIgnoreCase(extension)) {
            return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
        } else if ("ppt".equalsIgnoreCase(extension)) {
            return "application/vnd.ms-powerpoint";
        } else if ("pptx".equalsIgnoreCase(extension)) {
            return "application/vnd.openxmlformats-officedocument.presentationml.presentation";
        } else if ("txt".equalsIgnoreCase(extension)) {
            return "text/plain";
        } else if ("mp4".equalsIgnoreCase(extension)) {
            return "video/mp4";
        } else if ("mp3".equalsIgnoreCase(extension)) {
            return "audio/mp3";
        }
        
        return "application/octet-stream";
    }

    /**
     * 提取文件名
     *
     * @param file 文件
     * @param baseDir 基础目录
     * @return 返回文件名
     */
    private String extractFilename(MultipartFile file, String baseDir) {
        String extension = getExtension(file);
        String fileName = UUID.randomUUID().toString().replaceAll("-", "") + "." + extension;
        
        return baseDir + "/" + DateUtils.datePath() + "/" + fileName;
    }

    /**
     * 获取文件扩展名
     *
     * @param file 文件
     * @return 返回文件扩展名
     */
    private String getExtension(MultipartFile file) {
        String extension = FilenameUtils.getExtension(file.getOriginalFilename());
        if (StringUtils.isEmpty(extension)) {
            extension = MimeTypeUtils.getExtension(file.getContentType());
        }
        return extension;
    }

    /**
     * 文件大小校验
     *
     * @param file 上传的文件
     * @throws FileSizeLimitExceededException 如果超出最大大小
     */
    private void assertAllowed(MultipartFile file) throws FileSizeLimitExceededException {
        long size = file.getSize();
        if (size > DEFAULT_MAX_SIZE) {
            throw new FileSizeLimitExceededException(DEFAULT_MAX_SIZE / 1024 / 1024);
        }
    }
} 